Appearance
把 ES6 送上天的通天塔
本节目标:理解“把 ES6 送上天的通天塔”的核心思路,并能把它用于实际开发或面试表达。
说明:原 OneNote 中有图片引用,但图片未包含在导出目录中;本页保留了可用的文字与代码内容。 Babel组成
Babel 就是一套解决方案,用来把 ES6 的代码转化为浏览器或者其它环境支持的代码。
注意:不是转化为 ES5 ,因为不同类型以及不同版本的浏览器对 ES6 新特性的支持程度都不一样,对于浏览器已经支持的部分,Babel 可以不转化,所以 Babel 会依赖浏览器的版本,后面会讲到。 这里可以先参考
browerslist项目。
历史 在学习任何一门知识前,我都习惯先了解它的历史,这样才能深刻理解它存在意义。 Babel 的作者是 FaceBook 的工程师 Sebastian McKenzie。他在 2014 年发布了一款 JavaScript 的编译器 6to5。从名字就能看出来,它主要的作用就是将 ES6 转化为 ES5。
这里的 ES6 指 ES2015,因为当时还没有正式发布, ES2015 的名字还未被正式确定
于是很多人评价,6to5 只是 ES6 得到支持前的一个过渡方案,它的作者非常不同意这个观点,认为 6to5 不光会按照标准逐步完善,依然具备非常大的潜力反过来影响并推进标准的制定。正因为如此 6to5 的团队觉得 '6to5' 这个名字并没有准确的传达这个项目的目标。加上 ES6 正式发布后,被命名为 ES2015,对于 6to5 来说更偏离了它的初衷。于是 2015 年 2 月 15 号,6to5 正式更名为 Babel。
Babel 是巴比伦文化里的通天塔; 安装依赖包 npm install --save-dev @babel/core @babel/cli @babel/preset-env 后面会介绍这些包的作用,先看用法
增加 babel 命令来编译 src 目录下的文件到 dist 目录
:
{ "name": "demo", "version": "1.0.0", "description": "", "main": "src/index.js", "scripts": { "babel": "babel src --out-dir dist", "test": "echo \"Error: no test specified\" && exit 1"},
"keywords": [], "author": "", "license": "ISC", "devDependencies": { "@babel/cli": "^7.8.4", "@babel/core": "^7.9.0", "@babel/preset-env": "^7.9.0" }
}增加 Babel 配置文件 在工程的根目录添加 babel.config.js 文件,增加 Babel 编译的配置,没有配置是不进行编译的。
const presets = [ ['@babel/env', { debug: true }]
]
const plugins = []
module.exports = { presets, plugins
}上例中 debug 配置是为了打印出 Babel 工作时的日志,可以方便的看来,Babel 转化了哪些语法。
presets主要是配置用来编译的预置,plugins主要是配置完成编译的插件,具体的含义后面会讲- 推荐用
Javascript文件来写配置文件,而不是JSON文件,这样可以根据环境来动态配置需要使用的presets和plugins
const presets = [['@babel/env', { debug: true }]]
constplugins = []
if (process.env["ENV"] === "prod") { plugins.push()
}
module.exports = { presets, plugins }编译的结果 配置好后,我们运行 npm run babel 命令,可以看到 dist 文件夹下生成了 index.js 文件,内容如下所示
// src/index.js
const add = (a, b) => a + b
// dist/index.js
"use strict";
var add = function add(a, b) { return a + b;
};==可以看到,==ES6 ==的== const ==被转化为== var ==,箭头函数被转化为普通函数。同时打印出来如下日志:==
$ yarn babel
yarn run v1.22.11
$ babel src --out-dir dist
@babel/preset-env: `DEBUG` optionUsing targets:
{}
Using modules transform: auto
Using plugins:
proposal-class-static-block { }
proposal-private-property-in-object { }
proposal-class-properties { }
proposal-private-methods { }
proposal-numeric-separator { }
proposal-logical-assignment-operators { }
proposal-nullish-coalescing-operator { }
proposal-optional-chaining { }
proposal-json-strings { }
proposal-optional-catch-binding { }
transform-parameters { }
proposal-async-generator-functions { }
proposal-object-rest-spread { }
transform-dotall-regex { }
proposal-unicode-property-regex { }
transform-named-capturing-groups-regex { }
transform-async-to-generator { }
transform-exponentiation-operator { }
transform-template-literals { }
transform-literals { }
transform-function-name { }
transform-arrow-functions { }
transform-block-scoped-functions { }
transform-classes { }
transform-object-super { }
transform-shorthand-properties { }
transform-duplicate-keys { }
transform-computed-properties { }
transform-for-of { }
transform-sticky-regex { }
transform-unicode-escapes { }
transform-unicode-regex { }
transform-spread { }
transform-destructuring { }
transform-block-scoping { }
transform-typeof-symbol { }
transform-new-target { }
transform-regenerator { }
transform-member-expression-literals { }
transform-property-literals { }
transform-reserved-words { }
proposal-export-namespace-from { }
transform-modules-commonjs
proposal-dynamic-import
Using polyfills: No polyfills were added, since the `useBuiltIns` option was not set.
Successfully compiled 1 file with Babel (1451ms).
Done in 2.27s.Babel 工作流程 前面提到 Babel 其实就是一个纯粹的 JavaScript 的编译器,任何一个编译器工作流程大致都可以分为如下三步:
Parser解析源文件Transfrom转换Generator生成新文件
Babel 也不例外,如下图所示:
因为 Babel 使用是
acorn这个引擎来做解析,这个库会先将源码转化为抽象语法树 (AST),再对 AST 作转换,最后将转化后的 AST 输出,便得到了被 Babel 编译后的文件。
Babel 为每一个新的语法提供了一个插件,在 Babel 的配置中配置了哪些插件,就会把插件对应的语法给转化掉。插件被命名为 @babel/plugin-xxx 的格式。 > 来自
<https://zhuanlan.zhihu.com/p/129089156>